home *** CD-ROM | disk | FTP | other *** search
/ Nautilus 1993 March / Nautilus-4-3 / Nautilus-4-3.bin / Multimedia / Feature / RlePict1.1 Folder / RlePict.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-08  |  11.1 KB  |  441 lines

  1. /*
  2.  * This software is copyrighted as noted below.  It may be freely copied,
  3.  * modified, and redistributed, provided that the copyright notice is 
  4.  * preserved on all copies.
  5.  * 
  6.  * There is no warranty or other guarantee of fitness for this software,
  7.  * it is provided solely "as is".  Bug reports or fixes may be sent
  8.  * to the author, who may or may not act on them as he desires.
  9.  *
  10.  * You may not include this software in a program or other software product
  11.  * without supplying the source, or without informing the end-user that the 
  12.  * source is available for no extra charge.
  13.  *
  14.  * If you modify this software, you should include a notice giving the
  15.  * name of the person performing the modification, the date of modification,
  16.  * and the reason for such modification.
  17.  */
  18. /*
  19.  * RLE File converter/translater
  20.  * John Peterson, Jan-Feb '91
  21.  *
  22.  * Copyright (c) 1991 John Peterson
  23.  *
  24.  * Stuff still to do:
  25.  * - Error recovery needs more work - sort out fatal errors (DONE)
  26.  * - Deal with memory allocation problems as a separate
  27.  *   error class, and have "emergancy stash" ready (DONE)
  28.  * - Should do something intelligent with basic color maps (DONE)
  29.  * - Be smarter about tying filenames to windows.
  30.  * - Check the machine/system configuration (DONE)
  31.  * - Windows should stack with offsets (so new ones don't
  32.  *   completly bury the old) (DONE)
  33.  * - Activate events should mess with the menus (DONE)
  34.  * - Finder stuff (File types, bundles, icons, etc). (DONE)
  35.  * _ Spencer's radius card.
  36.  * - Jamie Painter sez it croaks on empty PICT files from MacDraw (FIXED)
  37.  * Stuff maybe someday...
  38.  * - Be less of a memory hog (don't hold your breath, this
  39.  *     is lotsa work..)
  40.  * - Grow boxes/scroll bars (also lotsa work)
  41.  * - Zoom modes, other GetX11 frobs...
  42.  */
  43.  
  44. #include <stdio.h>
  45. #include <string.h>
  46. #include <QDOffscreen.h>
  47.  
  48. #include "rle.h"
  49. #include "macstuff.h"
  50. #include "macimg.h"
  51.  
  52. Ptr PanicStash;        /* Buffer to bring up an "out of memory" dialog */
  53.  
  54. rle_hdr inglob;        /* Globals for RLE lib */
  55.  
  56. /*
  57.  * Create a window for displaying an image.  RlePict's
  58.  * info is stashed in the WRefCon.
  59.  */
  60. static void
  61. CreateWindow( GWorldPtr gw, char * name )
  62. {
  63.     WindowPtr win;
  64.     ImageWin * imgWin;
  65.  
  66.     win = MakeWindow( gw->portRect.right - gw->portRect.left, 
  67.                       gw->portRect.bottom - gw->portRect.top, name );
  68.     CopyGWtoWindow( gw, win );
  69.  
  70.     imgWin = (ImageWin *) NewPtr( sizeof( ImageWin ));
  71.     if (!imgWin) MemoryError( "Can't create window - out of memory" );
  72.     imgWin->tag = 0xDEADBEEF;
  73.     imgWin->win = win;
  74.     imgWin->gw = gw;
  75.     imgWin->name = (char *) malloc( strlen( name ) + 1L );
  76.     if (! imgWin->name )
  77.         MemoryError( "Can't allocate window name" );
  78.     strcpy( imgWin->name, name );
  79.     SetWRefCon( win, (long) imgWin );
  80. }
  81.  
  82. /* 
  83.  * RLE to PICT file
  84.  */
  85. void
  86. RLEtoPICT()
  87. {
  88.     GWorldPtr mygw;
  89.     char namestore[256];
  90.     char * filename = namestore;
  91.     register rle_pixel *rptr, *gptr, *bptr, *aptr, *qdptr;
  92.     register long i, j;
  93.     PixMapPtr ppm;
  94.     long mapSize;
  95.     CTabPtr macCtab = NULL;
  96.     CTabHandle macCtabHandle = NULL;
  97.     rle_pixel **rows;
  98.     Rect r;
  99.     QDErr err;
  100.     WindowPtr win;
  101.     ImageWin * imgWin;
  102.     DialogPtr progressDlog;
  103.     char MMUMode = 1;        /* 1 = 32 bit mode */
  104.  
  105.     if ( !OldFilename( "RLE file:", filename, '????' ) )
  106.         return;
  107.     inglob.rle_file = fopen( filename, "rb" );
  108.     CHECK( inglob.rle_file, "Can't open RLE file\n" );
  109.     err = rle_get_setup( &inglob );
  110.     
  111.     /*
  112.      * Report error if it dies...
  113.      */
  114.     if (err != RLE_SUCCESS)
  115.     {
  116.         switch ( err )
  117.         {
  118.         case RLE_NOT_RLE:
  119.             ErrorAlert( "Tried to read a non-RLE file" );
  120.             break;
  121.             
  122.         case RLE_EMPTY:
  123.             ErrorAlert( "RLE file was empty" );
  124.             break;
  125.             
  126.         case RLE_EOF:
  127.             ErrorAlert( "RLE header was incomplete" );
  128.             break;
  129.             
  130.         default:
  131.             ErrorAlert( "Error encountered reading RLE file header" );
  132.             break;
  133.         }
  134.         fclose( inglob.rle_file );
  135.         return;
  136.     }
  137.     
  138.     if ( rle_row_alloc( &inglob, &rows ) )
  139.         MemoryError( "Ran out of memory\n" );
  140.         
  141.     r.left = inglob.xmin;
  142.     r.right = inglob.xmax + 1;
  143.     r.top = inglob.ymin;
  144.     r.bottom = inglob.ymax + 1;
  145.     
  146.     /*
  147.      * Do some sanity checks on the kind of file we're reading
  148.      * (We don't do funky channels or cmaps).
  149.      */
  150.     if (inglob.ncmap)
  151.         if ((inglob.cmaplen != 8) 
  152.             && (inglob.ncmap != 3)
  153.             && (inglob.ncmap != 1))
  154.         {
  155.             ErrorAlert( "Sorry - this image's color map not supported" );
  156.             fclose( inglob.rle_file );
  157.             return;
  158.         }
  159.         
  160.     if ((inglob.ncolors != 3) && (inglob.ncolors != 1))
  161.     {
  162.         ErrorAlert( "Sorry - only one and three channel RLE images" );
  163.         fclose( inglob.rle_file );
  164.         return;
  165.     }
  166.     
  167.     /* 
  168.      * If given a valid color map, convert it into a QuickDraw
  169.      * color map.
  170.      */
  171.     if (inglob.ncmap)
  172.     {        
  173.         mapSize = 1 << inglob.cmaplen;
  174.         
  175.         macCtabHandle = (CTabHandle) 
  176.                             NewHandle( sizeof( ColorTable ) + sizeof( ColorSpec ) * mapSize );
  177.         if ( !macCtabHandle )
  178.             MemoryError( "No memory for color map" );
  179.  
  180.         HLock( macCtabHandle );            /* I hate handles */
  181.         macCtab = *macCtabHandle;
  182.         macCtab->ctSeed = GetCTSeed();
  183.         macCtab->ctFlags = 0;            /* Not a device... */
  184.         macCtab->ctSize = mapSize - 1;
  185.         
  186.         for (i = 0; i < mapSize; i++)
  187.         {
  188.             macCtab->ctTable[i].value = i;
  189.             macCtab->ctTable[i].rgb.red = inglob.cmap[i];
  190.             macCtab->ctTable[i].rgb.green = (inglob.ncmap == 3) ? inglob.cmap[i+mapSize]
  191.                                                              : inglob.cmap[i];
  192.             macCtab->ctTable[i].rgb.blue = (inglob.ncmap == 3) ? inglob.cmap[i+2 * mapSize]
  193.                                                              : inglob.cmap[i];
  194.         }
  195.         HUnlock( macCtabHandle );
  196.     }
  197.     else
  198.     {
  199.         if (inglob.ncolors == 1)        /* One chan, no cmap, must be B&W */
  200.             macCtabHandle = GetCTable( 8 + 32 );    /* Built-in grayscale */
  201.         else
  202.             macCtabHandle = NULL;        /* No table */
  203.     }
  204.  
  205.     /* 
  206.      * Allocate an off-screen image ("GWorld" in MacSpeak) for
  207.      * storing the image.  Should check the error return.
  208.      */
  209.     err = NewGWorld( &mygw, (inglob.ncolors == 3) ? 32 : 8, &r, macCtabHandle, NULL, 0 );
  210.     if (err)
  211.         MemoryError( "Error converting RLE file, no memory for off-screen buffer" );
  212.     
  213.     /* CTable was copied into gworld, so get rid of our copy */
  214.     if (macCtabHandle)
  215.         DisposCTable( macCtabHandle );
  216.     
  217.     if (! LockPixels( mygw->portPixMap ))
  218.         MemoryError( "Can't lock memory for image" );
  219.  
  220.     progressDlog = InitProgress( 300 );        /* "Reading RLE" progress */
  221.     
  222.     HLock( mygw->portPixMap );
  223.     ppm = *(mygw->portPixMap);
  224.     
  225.     for (i = inglob.ymax; i >= inglob.ymin; i--)
  226.     {
  227.         rle_getrow( &inglob, rows );
  228.         if (inglob.ncolors == 3)
  229.         {
  230.             rptr = &(rows[0][inglob.xmin]);
  231.             gptr = &(rows[1][inglob.xmin]);
  232.             bptr = &(rows[2][inglob.xmin]);
  233.         }
  234.         else
  235.             rptr = gptr = bptr = &(rows[0][inglob.xmin]);
  236.         aptr = inglob.alpha ? rows[-1] : NULL;
  237.         
  238.         qdptr = (rle_pixel *) &(ppm->baseAddr[(long) (i - inglob.ymin) * (long) (ppm->rowBytes & 0x7FFF) + (long)0]);
  239.         /*
  240.          * Note qdptr may be pointing off to memory out on a 32 bit NuBus card.
  241.          * If so, then the MMU must be swapped into 32 bit mode to access the
  242.          * memory.  Leave it to Spencer to turn this up...
  243.          */
  244.         SwapMMUMode( &MMUMode );
  245.                 
  246.         if (inglob.ncolors == 1)
  247.         {
  248.             if (inglob.ncmap)
  249.                 for (j = inglob.xmin; j <= inglob.xmax; j++)
  250.                     *qdptr++ = *rptr++;
  251.             else
  252.                 for (j = inglob.xmin; j <= inglob.xmax; j++)    /* Convert to screwy Color QD */
  253.                     *qdptr++ = 255 - *rptr++;
  254.         }
  255.         else
  256.             /* 32 bit QuickDraw stores pixels in ARGBARGB... format */
  257.             for (j = inglob.xmin; j <= inglob.xmax; j++)
  258.             {
  259.                 *qdptr++ = aptr ? *aptr++ : 0xFF;
  260.                 *qdptr++ = *rptr++;
  261.                 *qdptr++ = *gptr++;
  262.                 *qdptr++ = *bptr++;
  263.             }
  264.  
  265.         SwapMMUMode( &MMUMode );
  266.  
  267.         if (i && (!(i % 10)))
  268.             UpdateProgress( progressDlog, 
  269.                             1.0 - ((double) (i - inglob.ymin))
  270.                             / (double) (inglob.ymax - inglob.ymin));
  271.     }
  272.     HUnlock( mygw->portPixMap );
  273.     fclose( inglob.rle_file );
  274.     UpdateProgress( progressDlog, 1.0 );
  275.     UnlockPixels( mygw->portPixMap );
  276.     CreateWindow( mygw, filename );
  277.     DoneProgress( progressDlog );
  278. }
  279.  
  280. /* 
  281.  * Save a GWorld as an RLE file.  The GWorld is assumed to be 32 bits
  282.  * deep.
  283.  */
  284. void
  285. PICTtoRLE(GWorldPtr mygw, char * defname)
  286. {
  287.     char namestore[256];
  288.     char * filename = namestore;
  289.     register rle_pixel *rptr, *gptr, *bptr, *aptr, *qdptr;
  290.     register long i, j;
  291.     PixMapPtr ppm;
  292.     rle_pixel **rows;
  293.     Rect r;
  294.     QDErr err;
  295.     DialogPtr progressDlog;
  296.     char MMUMode = 1;
  297.  
  298.     r = mygw->portRect;
  299.     
  300.     inglob = rle_dflt_hdr;        /* Initialize random stuff */
  301.     inglob.xmin = r.left;
  302.     inglob.xmax = r.right - 1;
  303.     inglob.ymin = r.top;
  304.     inglob.ymax = r.bottom - 1;
  305.     inglob.ncolors = 3;
  306.     inglob.alpha = 0;            /* QD32 stomped on it! */
  307.     
  308.     if (defname)
  309.         strcpy( filename, defname );
  310.     else
  311.         strcpy( filename, "RLE file" );
  312.     if (! NewFilename( "RLE filename:", filename ) )
  313.         return;
  314.         
  315.     CHECK( inglob.rle_file = fopen( filename, "wb" ), "Can't open output file" );
  316.     progressDlog = InitProgress( 200 );
  317.     rle_put_setup( &inglob );
  318.     if ( rle_row_alloc( &inglob, &rows ) )
  319.         MemoryError( "Can't allocate scanlines" );
  320.     
  321.     if ( !LockPixels( mygw->portPixMap ) )
  322.         MemoryError( "Can't lock pixels in memory" );
  323.  
  324.     HLock( mygw->portPixMap );
  325.  
  326.     ppm = *(mygw->portPixMap);
  327.  
  328.     for (i = inglob.ymax; i >= inglob.ymin; i--)
  329.     {
  330.         rptr = &(rows[0][0]);
  331.         gptr = &(rows[1][0]);
  332.         bptr = &(rows[2][0]);
  333.         
  334.         qdptr = (rle_pixel *) &(ppm->baseAddr[(long) (i - (long) inglob.ymin)
  335.                                     * (long) (ppm->rowBytes & 0x7FFF) + (long)0]);
  336.                                     
  337.         SwapMMUMode( &MMUMode );    /* ╔In case qdptr is off to a NuBus card */
  338.         
  339.         for (j = inglob.xmin; j <= inglob.xmax; j++)
  340.         {
  341.             qdptr++;
  342.             *rptr++ = *qdptr++;
  343.             *gptr++ = *qdptr++;
  344.             *bptr++ = *qdptr++;
  345.         }
  346.  
  347.         SwapMMUMode( &MMUMode );
  348.  
  349.         rle_putrow( rows, r.right - r.left, &inglob );
  350.         if (i && (!(i % 10)))
  351.             UpdateProgress( progressDlog, 
  352.                             1.0 - ((double) (i - inglob.ymin))
  353.                             / (double) (inglob.ymax - inglob.ymin));
  354.     }
  355.     HUnlock( mygw->portPixMap );
  356.  
  357.     UpdateProgress( progressDlog, 1.0 );
  358.     fclose( inglob.rle_file );
  359.     DoneProgress( progressDlog );
  360. }
  361.  
  362. /*
  363.  * The File menu drives the functionality of the
  364.  * program.
  365.  */
  366. void
  367. DoFileItem( short item )
  368. {
  369.     char namestore[256];
  370.     char * filename = namestore;
  371.     GWorldPtr gw;
  372.     ImageWin * imgWin;
  373.      GWorldFlags flags = (1L << (long)clipPixBit) | (1L << (long)ditherPixBit);   
  374.  
  375.     switch (item) 
  376.     {
  377.     case 1:            /* Open PICT */
  378.         if (!OldFilename( "PICT file:", filename, 'PICT' ))
  379.             return;
  380.         gw = LoadPicture( filename );
  381.         if (gw)
  382.             CreateWindow( gw, filename );
  383.         break;
  384.         
  385.     case 2:            /* Save PICT */
  386.         if (! (imgWin = (ImageWin *) GetWRefCon( FrontWindow() )))
  387.             return;
  388.             
  389.         if (imgWin->tag != 0xDEADBEEF)
  390.             return;
  391.             
  392.         if (imgWin->name)
  393.             strcpy( filename, imgWin->name );
  394.             
  395.         if (!NewFilename( "Save PICT file as:", filename ))
  396.             return;
  397.             
  398.         SavePicture( imgWin->gw, filename );
  399.         
  400.         break;
  401.         
  402.     case 4:            /* Load RLE */
  403.         RLEtoPICT();
  404.         break;
  405.         
  406.     case 5:            /* Save RLE */
  407.         if (! (imgWin = (ImageWin *) GetWRefCon( FrontWindow() )))
  408.             return;
  409.             
  410.         if (imgWin->tag != 0xDEADBEEF)
  411.             return;
  412.         /*
  413.          * Force image to be 32 bits per pixel.  Can only happen if we're
  414.          * writing an RLE file we read, which is a pretty silly thing
  415.          * to do anyway...
  416.          */
  417.         gw = imgWin->gw;
  418.         if ( (*(gw->portPixMap))->pixelSize != 32 )
  419.             flags = UpdateGWorld( &(imgWin->gw), 32, &gw->portRect, NULL, NULL, flags );
  420.             
  421.         if (flags & (1L << gwFlagErrBit))
  422.             MemoryError( "Can't expand pixmap to 32 bits" );
  423.     
  424.         PICTtoRLE( imgWin->gw, imgWin->name );
  425.         break;
  426.         
  427.     case 7:
  428.         ExitToShell();
  429.         break;
  430.     }
  431. }
  432.  
  433.  
  434. main()
  435. {
  436.     InitMac();
  437.     PanicStash = NewPtr( 5000L );    /* Hopefully enough to bring up an error & exit */
  438.     CreateMenus();
  439.     EventLoop();
  440. }
  441.